package com.ashlikun.zxing.analyze

import android.graphics.ImageFormat
import android.graphics.Rect
import androidx.camera.core.ImageProxy
import com.ashlikun.camera.scan.AnalyzeResult
import com.ashlikun.camera.scan.FrameMetadata
import com.ashlikun.camera.scan.analyze.AbsNv21Analyzer
import com.ashlikun.camera.scan.analyze.Analyzer.OnAnalyzeListener
import com.ashlikun.camera.scan.analyze.Nv21Analyzer
import com.ashlikun.camera.scan.util.CameraXImageUtils
import com.ashlikun.camera.scan.util.CameraXUtils
import com.google.zxing.Result
import java.util.Arrays
import java.util.Queue
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 图像分析器
 */
class ResultAnalyzer(data: Nv21Analyzer?) : AbsNv21Analyzer<Result>(data) {
    private val queue: Queue<ByteArray> = ConcurrentLinkedQueue()
    private val joinQueue = AtomicBoolean(false)
    var dataAnalyzer: DataAnalyzer? = null
        private set

    fun setAnalyzer(dataAnalyzer: DataAnalyzer?) {
        this.dataAnalyzer = dataAnalyzer
    }

    class DataAnalyzerResult(results: Array<Result>?, rect: Rect?) {
        //识别结果
        var results: Array<Result>? = null

        //识别区域
        var rect: Rect? = null

        init {
            this.results = results
            this.rect = rect
        }
    }

    interface DataAnalyzer {
        /**
         * 分析图像数据
         *
         * @param data   旋转后的数据
         * @param width
         * @param height
         */
        fun analyze(data: ByteArray?, width: Int, height: Int): DataAnalyzerResult?
        val isMultipleCode: Boolean
    }

    override fun analyze(imageProxy: ImageProxy, listener: OnAnalyzeListener<Result>) {
        if (dataAnalyzer == null) dataAnalyzer = MultiFormatAnalyzer()
        if (!joinQueue.get()) {
            val imageSize = imageProxy.width * imageProxy.height
            val bytes = ByteArray(imageSize + 2 * (imageSize / 4))
            queue.add(bytes)
            joinQueue.set(true)
        }
        if (queue.isEmpty()) {
            return
        }
        var nv21Data = queue.poll()
        try {
            val rotation = imageProxy.imageInfo.rotationDegrees
            val width = imageProxy.width
            val height = imageProxy.height
            CameraXImageUtils.yuv_420_888toNv21(imageProxy, nv21Data)
            nv21Data = callNv21(nv21Data, width, height)
            val result: DataAnalyzerResult?
            if (rotation == 90 || rotation == 270) {
                val rotatedData = ByteArray(nv21Data.size)
                for (y in 0 until height) {
                    for (x in 0 until width) {
                        rotatedData[x * height + height - y - 1] = nv21Data[x + y * width]
                    }
                }
                result = dataAnalyzer!!.analyze(rotatedData, height, width)
            } else {
                result = dataAnalyzer!!.analyze(nv21Data, height, width)
            }
            if (result != null && !CameraXUtils.isEmpty(result.results)) {
                val frameMetadata = FrameMetadata(
                    width,
                    height,
                    rotation
                )
                joinQueue.set(false)
                listener.onSuccess(AnalyzeResult(nv21Data, ImageFormat.NV21, frameMetadata, result.rect, result.results?.toList().orEmpty()))
            } else {
                queue.add(nv21Data)
                listener.onFailure(null)
            }
        } catch (e: Exception) {
            queue.add(nv21Data)
            listener.onFailure(null)
        }
    }
}
